# coding=utf-8

# 解决服务器日志文件占用磁盘过大的问题

import paramiko
import time
import os
import datetime


# 获取一个和远程服务器的ssh链接
def get_ssh_connect(hostname, port, user, passwd, timeout=10):
    paramiko.util.log_to_file("SolveLogFileSize.log")

    s = paramiko.SSHClient()
    # s = paramiko.Transport((hostname,port))
    s.set_missing_host_key_policy(paramiko.AutoAddPolicy)
    s.connect(hostname=hostname, port=port, username=user, password=passwd)
    return s


# 获取日志列表  ,  远程服务器只保留当天日志，过去日志全部压缩打包为tar.gz文件，然后ssh远程下载tar.gz文件后从服务器上删除
def get_log_list(ssh):
    # 进入 /logs 目录
    # exec_command(ssh, "cd /logs")
    # 获取日志目录内容
    log_list = str(return_exec_command(ssh, "cd /logs && ls"), encoding="utf-8").rstrip("\n").split("\n")

    # 获得今天的日期
    current_day = time.strftime("%Y%m%d")

    # 要排除掉 antstorm_log ，antstorm_fx_mqtt_log , antstorm_fx_schedule_log , antstorm_fx_sql_log  , antstorm_mqtt_log , antstorm_schedule_log , antstorm_sql_log
    removed_list = {"antstorm_log": True, "antstorm_fx_log": True, "antstorm_fx_schedule_log": True,
                    "antstorm_fx_sql_log": True, "antstorm_mqtt_log": True, "antstorm_schedule_log": True,
                    "antstorm_sql_log": True}

    need_remove_list = []

    #  标记需要排除的元素,
    for log in log_list:
        if log in removed_list.keys():
            need_remove_list.append(log)
        # 从log_list 中排除掉  java开头的log,monitor开头的log, restart开头的log  ( gc开头的日志文件名称规律还没未找到)
        if str(log).startswith("java") or str(log).startswith("monitor") or str(log).startswith("restart") or str(
                log).startswith("gc"):
            need_remove_list.append(log)
        # 排除掉以 .log 结尾，但是文件名是今天的日志
        if str(log).endswith(".log") and str(log).startswith(current_day):
            need_remove_list.append(log)

    # 排除元素
    for i in need_remove_list:
        log_list.remove(i)

    return log_list


# 获取昨天的日期 ，格式：yyyyMMdd
def get_yesterday_date():
    today=datetime.date.today()
    oneday=datetime.timedelta(days=1)
    return str(today-oneday)

# 将需要处理的log文件进行打包压缩
def tar_log_list(ssh, log_list):
    # 拼接命令
    command = "cd /logs && tar -zcvf "

    # 压缩包的名称  日期格式：yyyyMMdd 如：20180808
    yesterday=get_yesterday_date()
    tar_name = yesterday + "_log.tar.gz "

    command = command + tar_name

    for log in log_list:
        command += str(log) + " "

    # 压缩后删除文件
    command += " --remove-files"

    print(" 压缩的日志的指令： " + command)

    # 执行指令
    stdin, stdout, stderr = ssh.exec_command(command)
    err_info = str(stderr.read(), encoding="utf-8").strip()
    if err_info:
        print("错误信息：" + str(stderr.read()))
        tar_name=err_info

    return tar_name.strip()


# 检查log的压缩文件是否生成
def check_log_tar(ssh, tar_name):
    # 将命令的输出内容中的 \n 去除
    tar_file = str(return_exec_command(ssh, "cd /logs && ls "), encoding="utf-8").replace("\n", " ")
    if tar_name in tar_file:
        print("压缩日志文件成功！")
        return True
    else:
        print("压缩日志文件失败!")
        return False


# 远程下载日志的压缩文件到本地指定路径后删除服务器的日志文件包 ,local_path 必须有 "/"
def download_log_tar(tar_name, remote_host, remote_port, remote_user, remote_passwd, local_path):
    # 创建远程的stfp链接
    sftp = get_stfp_ssh(remote_host, remote_port, remote_user, remote_passwd)

    local_file=local_path + remote_host + "_" + tar_name

    # 下载
    sftp.get("/logs/" + tar_name, local_file)

    # 关闭
    sftp.close()

    # 检查是否下载成功
    check_result = os.path.exists(local_file)
    print("下载命令执行结果 : " + str(check_result))
    return check_result


# 创建stfp的ssh
def get_stfp_ssh(remote_host, remote_port, remote_user, remote_passwd, ):
    transport = paramiko.Transport((remote_host, remote_port))
    transport.connect(username=remote_user, password=remote_passwd)
    return paramiko.SFTPClient.from_transport(transport)


# 删除远程的日志的压缩文件
def delate_remote_log_tar(ssh, tar_name):
    exec_command(ssh, "rm -rf " + tar_name)


# 有交互的ssh
def contact_exec_command(ssh, execmd, write_content):
    stdin, stdout, stderr = ssh.exec_command(execmd)
    if write_content:
        stdin.write(write_content)
    out_info = str(stdout.read(), encoding="utf-8")
    if str(stderr.read(), encoding="utf-8"):
        out_info = str(stderr.read(), encoding="utf-8");
    return out_info


# ssh执行命令 ，无返回结果
def exec_command(ssh, execmd):
    ssh.exec_command(execmd)


# ssh中执行命令,有返回结果
def return_exec_command(ssh, execmd):
    stdin, stdout, stderr = ssh.exec_command(execmd)
    stdin.write("Y")

    ls_content = stdout.read()
    return ls_content


# 关闭ssh链接
def close_ssh(ssh):
    ssh.close()


# 入口
def main(hostname, port, user, passwd, local_path):
    # 获取远程ssh
    remote_ssh = get_ssh_connect(hostname, port, user, passwd)

    # 获取日志列表
    log_list = get_log_list(remote_ssh)

    # 压缩远程日志
    tar_name = tar_log_list(remote_ssh, log_list)

    # 检查远程日志压缩是否成功
    remote_check_result = check_log_tar(remote_ssh, tar_name)

    # 如果压缩成功，执行下载
    if remote_check_result and download_log_tar(tar_name, hostname, port, user, passwd, local_path):
        # 下载成功，删除远程日志文件
        delate_remote_log_tar(remote_ssh, "/logs/" + tar_name)
        return True
    else:
        return False

    # 关闭ssh
    close_ssh(remote_ssh)


if __name__ == "__main__":
    # 测试python登陆本地ssh
    # localssh=get_ssh_connect("localhost",22,"mac","admin")
    # result=str(return_exec_command(localssh,"ls "),encoding="utf-8")
    # print("本地ssh连接执行命令的结果: " +result)

    # 要保持日志的服务器列表
    server_list = []

    # 测试服务器配置
    server1 = {"hostname": "120.76.214.192", "port": 22, "user": "root", "passwd": "Geetion2016"}

    # 第二台服务器
    # server2 = {"hostname": "", "port": 22, "user": "", "passwd": ""}

    server_list.append(server1)

    # server_list.append(server2)

    # 日志存储路径最后必须代 "/"
    local_path = "/home/vitokong/server_logs/"
    # local_path = "/Users/mac/Desktop/"
    # 下载服务器的日志

    for i in server_list:

        try:
            save_log_result = main(i["hostname"], i["port"], i["user"], i["passwd"], local_path)
            if save_log_result:
                print(i["hostname"] + " 日志文件远程下载成功！！！" + str(get_yesterday_date()))
            else:
                print(i["hostname"] + " 日志文件远程下载失败！！！" + str(get_yesterday_date()))

        except Exception:
            print(i["hostname"] + " 日志文件远程下载发生异常！！！" + str(get_yesterday_date()))
